home *** CD-ROM | disk | FTP | other *** search
- /* NCRChipManager.c */
- /*
- * NCRChipManager.c
- * Copyright © 1994 Apple Computer Inc. All rights reserved.
- */
- /* .___________________________________________________________________________________.
- | These low-level routines access the NCR 53C825 chip registers. They are needed |
- | to configure the chip on startup and to manage scripts. This is not a very good |
- | example of production-device programming: much of this could be done by resetting |
- | the chip and running a script. However, by doing this directly, we can do all |
- | I/O immediately. We'll use the Expansion Manager interface, even though the |
- | memory interface would be more efficient. |
- | |
- | Almost everything here is specific to the NCR chip. NCRChipPowerUp might be |
- | generally useful. |
- | |
- | Not all of this has been tested. |
- .___________________________________________________________________________________.
- */
-
- #include "NCRDriverPrivate.h"
- /*
- * Chip operations are performed by copying bytes from our table to the NCR chip.
- * a register value of 0xFF terminates the operation.
- */
-
- struct NCRRegisterOp {
- unsigned char chipRegister;
- unsigned char value;
- };
- typedef struct NCRRegisterOp NCRRegisterOp, *NCRRegisterOpPtr;
-
- /*
- * The chip initialization sequence is taken from the NCR 53C825 Family Programming
- * Guide, revision 1.0, table 7-10.
- * The registers and bits are defined in the NCR 53C825 Data Manual, revision 1.1.
- * You will need to read this documentation to understand what is going on here.
- */
- enum{
- EOF_OP = 0xFF
- };
-
- /*
- * Initialization - this is the minimum we can get away with. It is insufficient for
- * a production system.
- */
- const NCRRegisterOp gChipInitialize[] = {
- { ISTAT, bit7 | bit6 }, /* Abort operation, reset NCR chip */
- { ISTAT, 0 }, /* Clear reset condition */
- { SCNTL0, bit7 | bit6 }, /* Full arbitration */
- /* Disable parity checking */
- /* Do not assert ATN on parity error */
- /* Initiator mode (only) */
- { SCNTL1, bit7 }, /* Extra clock cycle of data setup */
- /* Clear bus reset condition */
- { SCNTL3, 1 }, /* No synchronous support, no wide SCSI */
- { SCXFER, 0 }, /* Synchronous transfer param's unused */
- { CTEST3, 0 }, /* Do not use PROM access */
- { CTEST4, 0 }, /* Enable data transfer burst mode */
- /* Disable high-impedence modes */
- /* No master data phase parity checking */
- { DMODE, 0 }, /* Burst Length == 2 */
- /* Source I/O Memory disabled */
- /* Destination I/O Memory disabled */
- /* Enable Read Line disabled */
- /* Burst Op Code Fetch disabled */
- /* Manual start mode disabled */
- { DIEN, bit6 | bit5 | bit4 | bit2 | bit0 }, /* All interrupts enabled */
- { DCNTL, 0 }, /* Single-step mode disabled */
- /* Totem-pole interrupt disabled */
- /* Start DMA operation disabled */
- /* 53C700 compatibility disabled */
- { SIEN0, bit3 | bit2 }, /* Enable SCSI Gross Error interrupt */
- /* Unexpected disconnect interrupt */
- { SIEN1, bit2 | bit1 }, /* Select & general timeout interrupts */
- { STIME0, 0x0D }, /* Selection timeout @ 409.6 msec. */
- { STIME1, 0 }, /* No general purpose timeout */
- { RESPID0, 0 }, /* We do not respond to selection */
- { RESPID1, 0 }, /* or reselection */
- { STEST1, 0 }, /* Use internal PCI bus clock */
- { STEST2, bit1 }, /* Disable SCSI Differential Mode */
- /* Enable extended REQ/ACK timing - do */
- /* not set this bit during fast SCSI */
- /* operation. It is more reliable for */
- /* slower operations */
- { STEST3, bit7 }, /* Enable TolerANT technology */
- /* Start SCSI clock */
- { EOF_OP, 0 }
- };
-
- const NCRRegisterOp gChipTerminate[] = {
- { DIEN, 0 }, /* Disable all interrupts */
- { SIEN0, 0 }, /* Disable SCSI interrupts */
- { SIEN1, 0 }, /* Disable all timeout interrupts */
- { ISTAT, bit7 | bit6 }, /* Abort operation, reset NCR chip */
- { ISTAT, 0 }, /* Clear chip reset condition */
- { CTEST4, bit5 }, /* Put data bus in high-impedence state */
- { STEST3, bit5 }, /* Halt SCSI clock */
- { EOF_OP, 0 }
- };
-
- /*
- * This command sequence is executed by KillIO - it stops the current script. This
- * will interrupt the computer and, eventually, complete any pending I/O. Note that
- * there is a fairly elaborate process you must follow after setting an abort, but
- * that will be handled in the I/O completion routine.
- */
- const NCRRegisterOp gChipStopCurrentScript[] = {
- { ISTAT, bit7 }, /* Abort operation */
- { EOF_OP, 0 }
- };
-
- void NCRConfigureChip(
- const NCRRegisterOp *opPtr
- );
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * NCRInitializeChip is called at initialization to check that we are actually connected
- * to a device we understand. It enables I/O and Memory space access and reads a chip
- * test register to verify that parameters were passed in correctly. This would also
- * be a good place to add chip self-tests.
- */
- OSErr
- NCRInitializeChip(void)
- {
- OSErr status;
- OSStatus osStatus;
- UInt8 ctest3;
- UInt16 commandWord;
- StringPtr failureMsg;
-
- Trace(NCRInitializeChip);
- failureMsg = NULL;
- /*
- * Before we do anything, we need to connect the PCI card to the great
- * universe of PCI bus operation. We are disconnected at power-up to
- * prevent run-away hardware from crashing the system. In a production
- * system, you probably won't enable both memory space and I/O space.
- */
- status = ExpMgrConfigReadWord(
- &GLOBAL.deviceEntry,
- (LogicalAddress) cwCommand,
- &commandWord
- );
- CheckStatus(status, "\pExpMgrConfigReadWord");
- if (status != noErr)
- failureMsg = "\pInitChip: can't read command word";
- if (status == noErr) {
- commandWord |=
- ( cwCommandSERREnable /* Enable parity error check */
- | cwCommandEnableParityError /* Enable parity error reports */
- | cwCommandEnableBusMaster /* Let chip become bus master */
- | cwCommandEnableMemorySpace /* Respond to base address 1 */
- | cwCommandEnableIOSpace /* Respond to base address 0 */
- );
- status = ExpMgrConfigWriteWord(
- &GLOBAL.deviceEntry,
- (LogicalAddress) cwCommand,
- commandWord
- );
- CheckStatus(status, "\pExpMgrConfigWriteWord");
- if (status != noErr)
- failureMsg = "\pInitChip: Can't write command word";
- }
- if (status == noErr) {
- /*
- * Test whether the pci card is accessable (without crashing). This
- * sequence reads a chip test register and verifies that the chip
- * revision level matches the expected value. In a production system,
- * this might be extended by a more elaborate self-test.
- */
- osStatus = DeviceProbe(
- (void *) (((UInt32) GLOBAL.pciCardBaseAddress) + CTEST3),
- &ctest3,
- k8BitAccess
- );
- CheckStatus(osStatus, "\pDeviceProbe CTEST3");
- if (osStatus != noErr) {
- status = osStatus;
- failureMsg = "\pInitChip: DeviceProbe failed";
- }
- }
- if (status == noErr) {
- if ((ctest3 & (bit7 | bit6 | bit5 | bit4)) != kPCIChipRevision) {
- LogHex(ctest3, "\pWrong ctest3 value at init");
- status = paramErr;
- failureMsg = "\pInitChip: Wrong chip revision";
- }
- }
- if (status != noErr)
- PublishInitFailureMsg(status, failureMsg);
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * NCRBusBusyCheck returns TRUE if the bus is busy and the NCR chip thinks that it
- * is connected. Note that this is called from application context, so there may
- * be a race condition. Returns noErr if the busy is busy, scsiUnableToTerminate
- * if the bus is not busy, or we are not connected.
- */
- OSErr
- NCRBusBusyCheck(void)
- {
- UInt8 istat;
-
- istat = ReadByte(ISTAT);
- LogHex(istat, "\pNCRBusBusyCheck istat");
- return ((istat & bit3) != 0) ? noErr : scsiUnableToTerminate;
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * NCRResetChip executes a variety of chip-specific configuration operations.
- *
- * Currently, we don't do anything that can cause an error, but this module would
- * typically be extended to include various chip-specific, and error-prone, tests.
- */
- OSErr
- NCRResetChip(
- NCRChipResetCommand resetChipCommand
- )
- {
- OSErr status;
-
- Trace(NCRResetChip);
- status = noErr;
- switch (resetChipCommand) {
- case kNCRResetChipInitialize: /* Called on driver initialize */
- NCRConfigureChip(gChipInitialize);
- /*
- * The initiator ID is stored in the System Registry - this lets
- * the user define the initiator ID at restart, which is needed if
- * we intend to use the driver in a processor-processor configuration.
- * Note that we disable reselection.
- */
- WriteByte(SCID, GLOBAL.initiatorID);
- break;
- case kNCRResetChipTerminate: /* Called on driver termination */
- NCRConfigureChip(&gChipTerminate[0]);
- break;
- case kNCRResetChipPowerDown: /* Handle PBControl driverPowerLow */
- NCRConfigureChip(&gChipTerminate[0]);
- break;
- case kNCRResetChipPowerUp: /* Handle PBControl driverPowerHigh */
- NCRConfigureChip(&gChipInitialize[0]);
- break;
- case kNCRStopCurrentScript:
- LogString("\pStopCurrentScript");
- NCRConfigureChip(gChipStopCurrentScript);
- LogString("\pAfter StopCurrentScript");
- break;
- }
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * NCRConfigureChip writes a stream of bytes to NCR chip registers.
- */
- void
- NCRConfigureChip(
- const NCRRegisterOp *opPtr
- )
- {
- Trace(NCRConfigureChip);
- for (; opPtr->chipRegister != EOF_OP; opPtr++)
- WriteByte((opPtr->chipRegister & 0x000000FFL), opPtr->value);
- }
-
-